﻿using System;
using System.Diagnostics;

namespace Common.Utilities.TextMatch
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class Validator : ICloneable
    {
        //Is the validator negated?
        private bool negated = false;

        #region Overloaded Operators

        //Operators aren't currently compiled as I can't decide whether they should conceptually be included or not. 
        //While they might be a sweet alternative to the Union/Interscet/Negate instance methods, it's seems to be
        //more conceptually correct to carry out logical operations on the results of the Validate method, so when and
        //as I see the light this will be rectified.

        /*
        // Logical negation operator.
        public static Validator operator !(Validator validator) {
            Validator negation = (Validator)validator.Clone();
            negation.negated = !negation.negated;
            return negation;
        }

        //Logical conjunction operator
        public static Validator operator &(Validator x, Validator y) {
            return new CompositeValidator(CompositeValidator.JoinType.And, x, y);
        }

        //Logical disjunction operator
        public static Validator operator |(Validator x, Validator y) {
            return new CompositeValidator(CompositeValidator.JoinType.Or, x, y);
        }

        // Logical true operator (allows && and || operators to be used)
        public static bool operator true(Validator x){
            return false;
        }
        // Logical false operator (allows && and || operators to be used)
        public static bool operator false(Validator x){
            return false;
        }
        */

        #endregion

        /// Make virtual so concrete descendants can deep copy if required...
        public virtual object Clone()
        {
            //Make a shallow copy
            return MemberwiseClone();
        }

        //Ensure negation is taken into account when validating
        /// <summary>
        /// 
        /// </summary>
        /// <param name="validationResult"></param>
        /// <returns></returns>
        protected bool NormalizeValidation(bool validationResult)
        {
            return this.negated ^ validationResult;
        }

        //Create a Validator which is the logical disjunction of the current instance and the Validator provided
        /// <summary>
        /// 
        /// </summary>
        /// <param name="validator"></param>
        /// <returns></returns>
        public Validator Union(Validator validator)
        {
            //Ensure the parameters are valid
            Debug.Assert(validator != null, "Unexpected null value.", "The Validator.Union(String) method requires a value.");

            if (validator == null)
                throw new ArgumentNullException("validator");

            return new CompositeValidator(CompositeType.Or, this, validator);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="validator"></param>
        /// <returns></returns>
        public Validator Intersect(Validator validator)
        {
            //Ensure the parameters are valid
            Debug.Assert(validator != null, "Unexpected null value.", "The Validator.Intersect(String) method requires a value.");

            if (validator == null)
                throw new ArgumentNullException("validator");

            return new CompositeValidator(CompositeType.And, this, validator);
        }

        //Create a Validator which is the negation of teh current instance
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Validator Negate()
        {
            Validator negation = (Validator)this.Clone();
            negation.negated = !negation.negated;
            return negation;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public abstract bool Validate(string value);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Validate(object value)
        {
            //Ensure the parameters are valid
            Debug.Assert(value != null, "Unexpected null value.", "The Validator.Validate(Object) method requires a value.");

            if (value == null)
                throw new ArgumentNullException("value");

            return Validate(value.ToString());
        }
    }
}
